
# third party
from __future__ import division
import math
import string

# this class got simple once I started forcing fragment's size and offset

class FragmentedPiece:

	def __init__ (self, size):
		self.size = size

		self.fragments = []
		self.fragmentsNeeded = []
		
		self.fragmentSize = 14 * 1024
		self.fragmentCount = int(math.ceil(self.size / self.fragmentSize))
		
		self.incompleteFragments = self.fragmentCount

		for i in range(self.fragmentCount):
			self.fragments.append( "" )

		self.refreshFragmentsNeeded()


	def getFragmentSize (self, index):
		if index == self.fragmentCount - 1:
			return self.size - (self.fragmentSize * (self.fragmentCount - 1))
		return self.fragmentSize

	def getFragmentSizeFromOffset (self, offset):
		if offset % self.fragmentSize != 0:
			raise Exception("ERROR: fragment offset was not aligned")
		return self.getFragmentSize( offset // self.fragmentSize )

		
	def addFragment (self, offset, data):
		if offset % self.fragmentSize != 0:
			raise Exception("ERROR: fragment offset was not aligned")
			
		index = offset // self.fragmentSize		
		if len(data) != self.getFragmentSize(index):
			raise Exception("ERROR: fragment was " + str(len(data)) + " but expected " + str(self.getFragmentSize(index)) )

		if self.fragments[index] == "":
			self.incompleteFragments -= 1

		if [offset, len(data)] in self.fragmentsNeeded:
			self.fragmentsNeeded.remove( [offset, len(data)]  )

		self.fragments[index] = data
		

	def isComplete (self):
		return self.incompleteFragments <= 0

	def getData (self):
		data = ""
		for fragment in self.fragments:
			data += fragment
		return data
		

	def nextFragmentRequest (self):
		if len(self.fragmentsNeeded) > 0:
			return self.fragmentsNeeded.pop()
	
	def requestFailed (self, fragment):
		self.fragmentsNeeded.append( fragment )

	def countUnsentRequests (self):
		return len(self.fragmentsNeeded)

	def refreshFragmentsNeeded (self):
		self.fragmentsNeeded = self.getAllFragmentRequests()
		self.incompleteFragments = len(self.fragmentsNeeded)

	def getAllFragmentRequests (self):
		requestList = []
		for i in range(self.fragmentCount):
			if self.fragments[i] == "":
				offset = i * self.fragmentSize
				size = self.getFragmentSize( i )
				requestList.append( [offset, size] )
		return requestList
		 

	
